快速ebuild向导

这页是个非常简洁的ebuild写作指南。它不包含许多开发者面临的细节和问题,而是给出足够用来理解ebuild如何工作的微小的例子。

为了正确的涵盖所有来龙去脉,参见Ebuild WritingGeneral Concepts章节也很有用。

注意这里的例子,虽然基于真实的ebuilds树,但有些部分大刀阔斧的修剪、更改和简化了。

第一个Ebuild

我们从Exuberant Ctags工具开始,一个代码索引工具。这时一个简化的dev-util/ctags/ctags-5.5.4.ebuild(你能在主目录下找到真实的ebuild)

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

EAPI=4

DESCRIPTION="Exuberant ctags generates tags files for quick source navigation"
HOMEPAGE="http://ctags.sourceforge.net"
SRC_URI="mirror://sourceforge/ctags/${P}.tar.gz"

LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~mips ~sparc ~x86"

src_configure() {
    econf --with-posix-regex
}

src_install() {
    emake DESTDIR="${D}" install

    dodoc FAQ NEWS README
    dohtml EXTENDING.html ctags.html
}

基本格式

如你所见,ebuilds仅仅是在特殊环境中执行的bash脚本。

在ebuild的顶部是头块(header block),出现在所有ebuild中。

Ebuild使用tabs缩进,每个tab代表四格空格。参见Ebuild File Format.

信息变量

接着,有一系列变量将告诉Portage有关包和ebuild的各种东西。

ebuild的EAPI,参见EAPI Usage and Description

DESCRIPTION变量是包及包的作用的简短描述。

HOMEPAGE是链接到包的主页的链接。(切记包含http://部分)。

SRC_URI告诉Portage用来下载源码包的地址。这里,mirror://sourceforge/是意为“任何Sourceforge镜像”的特殊标记。${P}是由Portage设置的只读变量,即包名和版本——示例中是ctags-5.5.4

LICENSE是协议GPL-2(GNU General Public License version 2)。

SLOT告诉Portage这个包安装到哪个slot。

KEYWORDS变量设置ebuild测试的架构。我们使用keyword给我们新写的ebuild,包不允许被直接推送到稳定版,即使他们似乎工作。参见Keywording查看细节。

构建函数

接着一个叫src_configure的函数,Portage将在配置(configure)包时调用它。econf是执行./configure的一个封装。如果由于某些原因在econf时出错,Portage将停止而非继续安装。

当Portage准备安装包时会调用src_install函数。这里有点微妙——并非直接安装到文件系统,我们必须安装到一个Portage通过${D}变量给出的特殊位置(Portage设置这个——参见Install DestinationsSandbox)

注意:常规安装方法是emake DESTDIR="${D}" install,这适合所有符合标准的Makefile。如果给出sandbox错误,尝试用einstall代替。如果仍然失败,参看src_install如何手工安装。

dodocdohtml部分是安装文件到相应的/usr/share/doc部分的辅助函数。

ebuild可以定义其它函数(参见Ebuild Functions)。在大多情况下,Portage提供合理的默认实现,通常做正确的事情,不需要定义src_unpacksrc_compile函数。例如,src_unpack函数被用来解包或给源码打补丁,但是这个例子中默认实现做了我们所需要的所有事情。同样默认的src_compile函数将调用emake——一个make的封装。

注意:先前|| die结构不得不添加到每个命令后去检查错误。这在EAPI 4中不在必要——如果什么出错的话Portage提供的函数将自己die。

含依赖的ebuild

在ctags的例子中,我们没告诉Portage有关任何依赖。当情况是这样时,没关系,因为ctags仅仅需要一个基本的工具链来编译和运行(参见Implicit System Dependency理解为何我们不需要显式依赖)。然而事情很少这么简单。

这是app-misc/detox/detox-1.1.1.ebuild

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

EAPI=4

DESCRIPTION="detox safely removes spaces and strange characters from filenames"
HOMEPAGE="http://detox.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.bz2"

LICENSE="BSD"
SLOT="0"
KEYWORDS="~hppa ~mips sparc x86"

RDEPEND="dev-libs/popt"
DEPEND="${RDEPEND}
    sys-devel/flex
    sys-devel/bison"

src_configure() {
    econf --with-popt
}

src_install() {
    emake DESTDIR="${D}" install
    dodoc README CHANGES
}

你再次看到ebuild头和不通的信息变量。在SRC_URI中,${PN}用来获取不含尾部版本的包名(还有更多的这种变量——参见Predefined Read-Only Variables)。

我们再次定义了src_configuresrc_install函数。

Portage依靠DEPENDRDEPEND变量决定构建和运行包需要哪些变量。DEPEND变量列出编译时依赖,RDEPEND变量列出运行时依赖。参见Dependencies获取更复杂的例子。

带补丁的ebuild

我们经常要打补丁。这通过epatch辅助函数在src_prepare函数中完成。为了使用epatch,必须告诉Portage需要的eutilseclass(eclass就像库一样)——这通过在ebuild顶部的inherit eutils完成。这是app-misc/detoxdetox-1.1.0.ebuild

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

EAPI=4

inherit eutils

DESCRIPTION="detox safely removes spaces and strange characters from filenames"
HOMEPAGE="http://detox.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.bz2"

LICENSE="BSD"
SLOT="0"
KEYWORDS="~hppa ~mips ~sparc ~x86"

RDEPEND="dev-libs/popt"
DEPEND="${RDEPEND}
    sys-devel/flex
    sys-devel/bison"

src_prepare() {
    epatch "${FILESDIR}"/${P}-destdir.patch \
        "${FILESDIR}"/${P}-parallel_build.patch
}

src_configure() {
    econf --with-popt
}

src_install() {
    emake DESTDIR="${D}" install
    dodoc README CHANGES
}

注意${FILESDIR}/${P}-destdir.patch指向detox-1.1.0-destdir.patch,这个文件在Portage树的files/子文件夹中。更大的补丁文件必须在你的开发者空间dev.gentoo.org而不是files/或镜像中——参见Gentoo MirrorsPatching with epatch

带USE标记的ebuild

USE标记,这里有个例子dev-libs/libiconv/libiconv-1.9.2.ebuild,一个libc实现的iconv替代。

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

EAPI=4

DESCRIPTION="GNU charset conversion library for libc which doesn't implement it"
HOMEPAGE="http://www.gnu.org/software/libiconv/"
SRC_URI="ftp://ftp.gnu.org/pub/gnu/libiconv/${P}.tar.gz"

LICENSE="LGPL-2.1"
SLOT="0"
KEYWORDS="~amd64 ~ppc ~sparc ~x86"
IUSE="nls"

DEPEND="!sys-libs/glibc"

src_configure() {
    econf $(use_enable nls)
}

src_install() {
    emake DESTDIR="${D}" install
}

注意IUSE变量。这列出了所有(非特殊)ebuild使用的use标记。除其它事项外,它还将被用作emerge -pv时输出。

这个包的./configure脚本使用了常规的--enable-nls--disable-nls参数。我们用use_enable工具函数依赖用户USE标记自动生成这个(参见Query Function Reference)。

另一个复杂的例子是mail-client/sylpheed/sylpheed-1.0.4.ebuild

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

EAPI=4

inherit eutils

DESCRIPTION="A lightweight email client and newsreader"
HOMEPAGE="http://sylpheed.good-day.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.bz2"

LICENSE="GPL-2"
SLOT="0"
KEYWORDS="alpha amd64 hppa ia64 ppc ppc64 sparc x86"
IUSE="crypt imlib ipv6 ldap nls pda ssl xface"

RDEPEND="=x11-libs/gtk+-2*
    crypt? ( >=app-crypt/gpgme-0.4.5 )
    imlib? ( media-libs/imlib2 )
    ldap? ( >=net-nds/openldap-2.0.11 )
    pda? ( app-pda/jpilot )
    ssl? ( dev-libs/openssl )
    xface? ( >=media-libs/compface-1.4 )
    app-misc/mime-types
    x11-misc/shared-mime-info"
DEPEND="${RDEPEND}
    dev-util/pkgconfig
    nls? ( >=sys-devel/gettext-0.12.1 )"

src_prepare() {
    epatch "${FILESDIR}"/${PN}-namespace.diff \
        "${FILESDIR}"/${PN}-procmime.diff
}

src_configure() {
    econf \
        $(use_enable nls) \
        $(use_enable ssl) \
        $(use_enable crypt gpgme) \
        $(use_enable pda jpilot) \
        $(use_enable ldap) \
        $(use_enable ipv6) \
        $(use_enable imlib) \
        $(use_enable xface compface)
}

src_install() {
    emake DESTDIR="${D}" install

    doicon sylpheed.png
    domenu sylpheed.desktop

    dodoc [A-Z][A-Z]* ChangeLog*
}

注意可选依赖。有些use_enable行使用两个参数的版本——这在USE标记名不完全匹配./configure参数时非常有用。

Image to CSS

Warning: 我警告过了,浏览器弱爆了的就不要点开了= =。内存太小了就慎重打开= =

眼残,竟然看到这种奇葩的演示

看了看CSS源码,想起来可以用Python Image Library做一个generator。

结果就真得做了一个……

Codes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#! /bin/env python
# -*- coding: utf-8 -*-

"""
Script to turn image into css
"""


import Image
import sys

__author__ = "Reverland (lhtlyy@gmail.com)"


def getcss(im):
"""docstring for get"""
css = """position: absolute;
top: 30px;
left: 30px;
width: 0;
height: 0;
box-shadow:
"""

string = '%dpx %dpx 0px 1px rgb%s,\n'
for y in range(0, im.size[1], 1):
for x in range(0, im.size[0], 1):
if im.size[1] - y <= 1 and im.size[0] - x <= 1:
string = '%dpx %dpx 0px 1px rgb%s;\n'
color = im.getpixel((x, y))
css += string % (x, y, color)
return css


def gethtml(css):
"""docstring for gethtml"""
html = """
<div style="
%s"></div>
""" % css

return html

if __name__ == '__main__':
filename = sys.argv[1]
#outfile = sys.argv[2]
im = Image.open(filename)
ratio = 0.5
size = (int(ratio * im.size[0]), int(ratio * im.size[1]))
im.thumbnail(size)
html = gethtml(getcss(im))
print html
# with open(outfile, 'wb') as f:
# f.write(html)

Demo

点击显示图像

意义?

意义在于可能你会死机= =

尝试复制看看?

Python小练习:追踪导弹仿真

警告:浏览器可能不支持html嵌入标签,那么很抱歉什么视频也看不到。建议使用最新稳定版的firefox/chromium

仿真的时候面向对象会很方便。

缘起

某天终于没有雾霾的时候,我在操场上追赶正在散步的父亲……然后,我就想多了= =跟踪导弹是个什么轨迹呢?

操场示意图

仿真

首先把问题简化下,如果从圆心开始追赶圆上匀速运动的物体,是什么情况。

我先自己设法用微分笔算了算,发现实在搞不定。

上网查查导弹问题看到一些简单的直线问题,都涉及一堆微分方程和欧拉法迭代啥的……

干脆自己仿真下吧。这是最初的版本,完全没有面向对象概念。

前半部分调整图像的代码完全可以不看,从while循环开始即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import matplotlib.pyplot as plt
import numpy as np
tolerance = 1e-1
radius = np.pi
v_o = 20
x_o, y_o = 0, radius

x_m, y_m = -radius, 0
v_m = 5

plt.figure(figsize=(10, 10), dpi=80)
plt.title(" missile flight simulator ", fontsize=40)
plt.xlim(-4, 4)
plt.ylim(-4, 4)
#plt.xticks([])
#plt.yticks([])

# set spines
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.xticks([-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi], [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])
plt.yticks([-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi], [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])

# Note object and missile
plt.annotate('object start point', xy=(x_o, y_o), xycoords='data',
xytext=(+15, +15), textcoords='offset points', fontsize=12,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.annotate('missile start point', xy=(x_m, y_m), xycoords='data',
xytext=(+15, +15), textcoords='offset points', fontsize=12,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

# alpha labels
for label in ax.get_xticklabels() + ax.get_yticklabels():
label.set_fontsize(16)
label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65))


while True:
if x_o == 0 and y_o == radius:
beta = 0
elif x_o == 0 and y_o == radius:
beta = np.pi
elif x_o < 0:
beta = np.pi / 2 * 3 - np.arctan(y_o / x_o)
else:
beta = np.pi / 2 - np.arctan(y_o / x_o)
if np.sqrt((x_o - x_m) ** 2 + (y_o - y_m) ** 2) < tolerance:
print "collision"
plt.plot(x_m, y_m, 'o')
plt.annotate('crash point', xy=(x_m, y_m), xycoords='data',
xytext=(+15, +15), textcoords='offset points', fontsize=12,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.pause(0.1)
break
elif x_o < x_m:
alpha = np.pi + np.arctan((y_o - y_m) / (x_o - x_m))
elif x_o == x_m:
alpha = np.pi / 2
else:
alpha = np.arctan((y_o - y_m) / (x_o - x_m))
x_o = radius * np.sin(beta + v_o * 0.01 / np.pi / 2)
y_o = radius * np.cos(beta + v_o * 0.01 / np.pi / 2)
x_m = x_m + v_m * 0.01 * np.cos(alpha)
y_m = y_m + v_m * 0.01 * np.sin(alpha)
#print alpha, beta
plt.plot(x_o, y_o, 'r.', alpha=.5)
plt.plot(x_m, y_m, 'bx', alpha=.5)
plt.legend(("target", "missile"), loc="upper left", prop={'size': 12})
plt.pause(0.1)

我发现如果我速度够慢,未必追得上,甚至连被追踪物的轨道都不会进入……这挺出乎意料的,本来以为一定追的上

回到最初的问题,我从我的位置上追我父亲(好傻,都不知道估计下位置……)

面向对象

问题来了,如果我要仿真不只一个追踪导弹,比如还想仿真一个拦截导弹呢?

拦截失败演示

还可以用上面的方法不断扩充代码,每个对象写重复的代码。

但这时面向对象就能发挥威力,减少代码重用了。

以下是对四蜗牛聚合线问题的仿真。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import matplotlib.pyplot as plt
import numpy as np
tolerance = 1e-1
radius = np.pi

# missile 1
x_m1, y_m1 = -np.pi, 0
v_m1 = 5

# missile 2
x_m2, y_m2 = 0, np.pi
v_m2 = v_m1
# missile 3
x_m3, y_m3 = np.pi, 0
v_m3 = v_m1
# missile 4
x_m4, y_m4 = 0, -np.pi
v_m4 = v_m1

plt.figure(figsize=(10, 10), dpi=80)
plt.title(" missile flight simulator ", fontsize=40)
plt.xlim(-4, 4)
plt.ylim(-4, 4)
#plt.xticks([])
#plt.yticks([])

# set spines
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.xticks([-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi], [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])
plt.yticks([-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi], [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])

plt.annotate('missile start point', xy=(x_m1, y_m1), xycoords='data',
xytext=(+15, +15), textcoords='offset points', fontsize=12,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

# alpha labels
for label in ax.get_xticklabels() + ax.get_yticklabels():
label.set_fontsize(16)
label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65))


class ob(object):
"""docstring for ob"""
def __init__(self, x, y):
self.x = x
self.y = y


class missile(ob):
"""docstring for missile"""
def __init__(self, x, y):
super(missile, self).__init__(x, y)

def forward(self, v, target):
"""docstring for forward"""
if self.x < target.x:
alpha = np.arctan((target.y - self.y) / (target.x - self.x))
elif self.x > target.x:
alpha = np.pi + np.arctan((target.y - self.y) / (target.x - self.x))
elif self.x == target.x and self.y < target.y:
alpha = np.pi / 2
else:
alpha = -np.pi / 2
self.x = self.x + v * 0.01 * np.cos(alpha)
self.y = self.y + v * 0.01 * np.sin(alpha)
return self.x, self.y

def distance(self, target):
"""docstring for distance"""
return np.sqrt((self.x - target.x) ** 2 + (self.y - target.y) ** 2)


class target(ob):
"""docstring for target"""
def __init__(self, x, y):
super(target, self).__init__(x, y)

def newposition(self, x, y):
"""docstring for newposition"""
self.x = x
self.y = y

m1 = missile(x_m1, y_m1)
m2 = missile(x_m2, y_m2)
m3 = missile(x_m3, y_m3)
m4 = missile(x_m4, y_m4)

while True:
if m1.distance(m2) < tolerance or m1.distance(m3) < tolerance or m1.distance(m4) < tolerance:
print "collision"
plt.plot(x_m1, y_m1, 'o')
plt.annotate('crash point', xy=(x_m1, y_m1), xycoords='data',
xytext=(+15, +15), textcoords='offset points', fontsize=12,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.pause(0.1)
plt.show()
break
elif m3.distance(m2) < tolerance or m3.distance(m4) < tolerance:
print "collision"
plt.plot(x_m3, y_m3, 'o')
plt.annotate('crash point', xy=(x_m3, y_m3), xycoords='data',
xytext=(+15, +15), textcoords='offset points', fontsize=12,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
plt.pause(0.1)
plt.show
break
x_m1, y_m1 = m1.forward(v_m1, m2)
x_m2, y_m2 = m2.forward(v_m2, m3)
x_m3, y_m3 = m3.forward(v_m3, m4)
x_m4, y_m4 = m4.forward(v_m4, m1)
#print alpha, beta
plt.plot(x_m1, y_m1, 'bx', alpha=.5)
plt.plot(x_m2, y_m2, 'k*', alpha=.5)
plt.plot(x_m3, y_m3, 'r.', alpha=.5)
plt.plot(x_m4, y_m4, 'gp', alpha=.5)
plt.legend(("missile1", "missile2", "missile3", "missile4"), loc="upper left", prop={'size': 12})
plt.pause(0.1)

总结

面向对象方法对仿真问题非常合适,能有效简化代码,做到DRY(Don’t repeat yourself)。

搞着玩的,也许我该想想复试怎么办了……

Generate Ascii Image Like the Matrix

Inspired by this online image to text converter and this post on Oschina

script hosts at github. Poor hack, Any advice is welcomed.

Edit: Oooops, Demo sucks on my site, it’s perfect if you generate an alone html file.look here and here

Demo





















































源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#! /bin/env python
# -*- coding: utf-8 -*-

"""
Turn images into acsii.
"""


__author__ = 'Reverland (lhtlyy@gmail.com)'

import Image
import ImageOps
import sys


filename = 'a.jpg'


def makeHTMLbox(body, fontsize, imagesize):
"""takes one long string of words and a width(px) then put them in an HTML box"""
boxStr = """<div style=\"font-size: %spx;line-height: 100%s; width: %s;background-color: rgb(0, 0, 0);border: 1px grey solid;text-align: center; overflow: hidden;\">%s</div>
"""

return boxStr % (fontsize, '%', imagesize[0], body)


def makeHTMLascii(body, color):
"""take words and , and create an HTML word """
#num = str(random.randint(0,255))
# return random color for every tags
color = 'rgb(%s, %s, %s)' % color
# get the html data
wordStr = '<span style=\"color:%s;float:left;\">%s</span>'
return wordStr % (color, body)


def i2m(im, fontsize):
"""turn an image into ascii like matrix"""
im = im.convert('L')
im = ImageOps.autocontrast(im)
im.thumbnail((im.size[0] / fontsize, im.size[1] / fontsize))
string = ''
colors = [(0, i, 0) for i in range(0, 256, 17)]
words = '据说只有到了十五字才会有经验的'
for y in range(im.size[1]):
for x in range(im.size[0]):
p = im.getpixel((x, y))
i = 14
while i >= 0:
if p >= i * 17:
s = makeHTMLascii(words[3 * i:3 * (i + 1)], colors[i])
break
i -= 1
if x % im.size[0] == 0 and y > 0:
s = s + '<br/>'
string = string + s
return string


def i2a(im, fontsize):
"""turn an image into ascii with colors"""
im = im.convert('RGB')
im = ImageOps.autocontrast(im)
im.thumbnail((im.size[0] / fontsize, im.size[1] / fontsize))
string = ''
for y in range(im.size[1]):
for x in range(im.size[0]):
c = im.getpixel((x, y))
# print c
s = makeHTMLascii('翻', c)
if x % im.size[0] == 0 and y > 0:
s = s + '<br/>'
string = string + s
return string


def getHTMLascii(filename, fontsize, style='matrix', outputfile='a.html', scale=1):
"""Got html ascii image"""
im = Image.open(filename)
size = (int(im.size[0] * scale), int(im.size[1] * scale))
im.thumbnail(size, Image.ANTIALIAS)
if style == 'matrix':
ascii = makeHTMLbox(i2m(im, fontsize), fontsize, im.size)
elif style == 'ascii':
ascii = i2a(im, fontsize)
else:
print "Just support ascii and matrix now, fall back to matrix"
ascii = makeHTMLbox(i2m(im, fontsize), fontsize, im.size)
with open(outputfile, 'wb') as f:
f.write(ascii)
return 1


if __name__ == '__main__':
if sys.argv[1] == '--help' or sys.argv[1] == '-h':
print """Usage:python i2a.py filename fontsize [optional-parameter]
optional-parameter:
scale -- between (0, 1)
style -- matrix or ascii"""

else:
filename = sys.argv[1]
try:
fontsize = int(sys.argv[2])
except:
fontsize = int(raw_input('input fontsize please:'))
try:
scale = float(sys.argv[3])
except:
scale = 1
try:
style = sys.argv[4]
except:
style = 'matrix'
getHTMLascii(filename, fontsize, scale=scale)

More Demo




























































Yet Another PhotoMosaic Generator

Update: Mon 25 Feb 2013 11:38:47 AM CST add classic style. More refer to github

Python是面向对象的?没有对象面向毛对象。

——Anonymous

Several weeks ago, I saw a poster of presidential campaign for Obama, in which Obama’s portrait was made up of many voter’s photos. It really attracted me, somedays later, I want to make one myself.

The completed code host here. It is much more functional than object-oriented…

Search the Internet

First of all, I searched the Google to find out how others achieve it, then I found many interesting implement and post on it.Along with them, there are pretty demos around.One of the demo of Foto-Mosaik-Edda striked me.It declaims as follows in their site:

The Chaos Mosaic Picture is a new form of photo mosaic which can, at present, only be created by Foto-Mosaik-Edda.

Chaos Mosaic Picture

Uhm…Foto-Mosaic-Edda is an open-source project that really impressive.But it was an C# project. Linux users don’t like it however.I don’t like mono.

I searched other open-source implement on photomosaic. I get some simple programs only use gray photos, and some complex ones can make beautiful classic photomosaic(like metapixel, even chaos style which it calls collage style), But none has as beautiful demos as Foto-Mosaic-Edda.(metapixel really amazing, it is robust and quickly.)

However, I saw many enthusiastic people write one themselves, it really looks interesting for me. I’ve used PIL for processing images when I tried to decode captchas several days ago, so I believe with the help of PIL, someone can achieve photomosaic simply.

So I just read the documentation of PIL, then start my hack.

Write My Own PhotoMosaic Generator

It’s not hard, however, what you should do is clear and simple:

  • analyse the image to be made mosaic, get a dict in which position as key and color as value.
  • use a bunch of images to get a dict, in which image name as key and colors as value.
  • thumbnail bunches of images and paste it in the right position, so that the big image looks like it consists of many small one.

I’d like to got the chaos style, so some other requirements:

  • frame and shadow for small images
  • random paste small images onto large one

Now, let’s go.

Frame, Shadow and Rotate

first add frame, shadow to small images

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def add_frame(image):
'''Add frame for image.'''
im = ImageOps.expand(image, border=int(0.01 * max(image.size)), fill=0xffffff)
return im


def drop_shadow(image, offset, border=0, shadow_color=0x444444):
"""Add shadows for image"""
# Caclulate size
fullWidth = image.size[0] + abs(offset[0]) + 2 * border
fullHeight = image.size[1] + abs(offset[1]) + 2 * border
# Create shadow, hardcode color
shadow = Image.new('RGBA', (fullWidth, fullHeight), (0, 0, 0))
# Place the shadow, with required offset
shadowLeft = border + max(offset[0], 0) # if <0, push the rest of the image right
shadowTop = border + max(offset[1], 0) # if <0, push the rest of the image down
shadow.paste(shadow_color, [shadowLeft, shadowTop, shadowLeft + image.size[0], shadowTop + image.size[1]])
shadow_mask = shadow.convert("L")
# Paste the original image on top of the shadow
imgLeft = border - min(offset[0], 0) # if the shadow offset was <0, push right
imgTop = border - min(offset[1], 0) # if the shadow offset was <0, push down
shadow.putalpha(shadow_mask)
shadow.paste(image, (imgLeft, imgTop))
return shadow

Then a function to rotate images.

1
2
3
4
5
6
def rotate_image(image, degree):
'''Rotate images for specific degree. Expand to show all'''
if image.mode != 'RGBA':
image = image.convert('RGBA')
im = image.rotate(degree, expand=1)
return im

‘RGBA’ mode is to support transparency. What’s matter here is that jpeg/jpg does not support transparency. So you can’t get transparency shadows and rotate pictures if you just use jpg/jpeg images.So, write a function to process images with jpg/jpeg format, transpose it into png.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def process_image(filename, newname):
'''convert image to png to support transparency'''
if filename.split('.')[-1] != 'png':
im = Image.open(filename)
im.save(newname + '.png')
print "processing image file %s" % filename
return 1


def process_directory(path):
os.chdir(path)
count = 1
for filename in os.listdir(path):
ext = filename.split('.')[-1]
if ext == 'jpeg' or ext == 'jpg':
process_image(filename, str(count))
os.remove(filename)
count += 1
return 1

Really poor work… But it works for me: )

We have to thumnail bunches of images, It’s easy to thumbnail with PIL:

1
2
3
4
def thumbnail(im, size):
"""thumnail the image"""
im.thumbnail(size, Image.ANTIALIAS)
return im

Let’s have a fun with them. To get heaps of images randomly on the desktop, I hardcoded these parameters to get my photos work, you HAVE TO find yours:

1
2
3
4
5
6
7
8
9
10
# Just for fun
def chao_image(path, size=(800, 800), thumbnail_size=(50, 50), shadow_offset=(10, 10), backgroud_color=0xffffff):
image_all = Image.new('RGB', size, backgroud_color)
for image in os.listdir(path):
if image.split('.')[-1] == 'png':
im = Image.open(image)
degree = random.randint(-30, 30)
im = thumbnail(rotate_image(drop_shadow(add_frame(im), shadow_offset), degree), thumbnail_size)
image_all.paste(im, (random.randint(-thumbnail_size[0], size[0]), random.randint(-thumbnail_size[1], size[1])), im)
return image_all

Calculate Images And Compare

Get average colors of an image

1
2
3
4
def average_image(im):
"""return average (r,g,b) for image"""
color_vector = [int(x) for x in ImageStat.Stat(im).mean]
return color_vector

to compare images? Compare the (r,g,b) value of them.

1
2
3
4
5
6
7
8
9
def compare_vectors(v1, v2):
"""compare image1 and image2, return relations"""
if len(v1) == len(v2):
distance = 0
for i in xrange(len(v1)):
distance += (v1[i] - v2[i]) ** 2
return distance
else:
print "vector not match in dimensions"

I just use distance in (R, G, B) space to calculate similarity, someone advice compare in other space, you can change it just like the example in PIL’s documentation:

1
2
3
4
5
6
# May not useful
def rgb2xyz(im):
"""rgb to xyz"""
rgb2xyz = (0.412453, 0.357580, 0.180423, 0, 0.212671, 0.715160, 0.072169, 0, 0.019334, 0.119193, 0.950227, 0)
out = im.convert("RGB", rgb2xyz)
return out

But I find many implements just use R,G,B, and it works well.

Next, get a dict of image in current path, in which filename as key, average (R,G,B) colors as value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def tile_dict(path):
"""Return list of average (R,G,B) for image in this path as dict."""
dic = {}
for image in os.listdir(path):
if image.split('.')[-1] == 'png':
try:
im = Image.open(image)
except:
print "image file %s cannot open" % image
continue
if im.mode != 'RGB':
im = im.convert('RGB')
dic[image] = average_image(im)
return dic

We don’t need to calculate every pixel of the large picture, just thumbnail it to get a nearest color of different regions.

1
2
3
4
5
6
def thumbnail_background(im, scale):
"""thumbnail backgroud image"""
newsize = im.size[0] / scale, im.size[1] / scale
im.thumbnail(newsize)
print 'thumbnail size and the number of tiles %d X %d' % im.size
return im.size

For every pixel in the thumbnailed large image, find most similar small image filenames.(top ten):

1
2
3
4
5
6
7
8
9
10
def find_similar(lst, dic):
"""for lst([R, G, B], Calculate which key-value in dic has the most similarity.Return first 10)"""
similar = {}
for k, v in dic.items():
similar[k] = compare_vectors(v, lst)
# if len(v) != len(lst):
# print v, len(v), lst, len(lst)
similar = [(v, k) for k, v in similar.items()] # Not good, lost the same Score
similar.sort()
return similar[:10]

Poor hack, but it really works…

Final Work

Now it’s the final magic.

Get the small image in order, the order imply where it should be. Then rotate, add shadows and frames for small images, finally paste it onto the large one randomly in the right position:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def get_image_list(im, dic):
"""receive a thumbnail image and a dict of image to be mosaic, return tiles(filename) in order(as a list)"""
lst = list(im.getdata())
tiles = []
for i in range(len(lst)):
#print find_similar(lst[i], dic)[random.randrange(10)][1]
tiles.append(find_similar(lst[i], dic)[random.randrange(10)][1])
return tiles


def paste_chaos(image, tiles, size, shadow_off_set=(30, 30)):
"""size is thumbnail of backgroud size that is how many tiles per line and row"""
# image_all = Image.new('RGB', image.size, 0xffffff)
image_all = image
lst = range(len(tiles))
random.shuffle(lst)
fragment_size = (image.size[0] / size[0], image.size[1] / size[1])
print 'tiles size %d X %d' % fragment_size
print 'number of tiles one iteration: %d' % len(lst)
for i in lst:
im = Image.open(tiles[i])
degree = random.randint(-20, 20)
im = thumbnail(rotate_image(drop_shadow(add_frame(im), shadow_off_set), degree), (fragment_size[0] * 3 / 2, fragment_size[1] * 3 / 2))
x = i % size[0] * fragment_size[0] + random.randrange(-fragment_size[0] / 2, fragment_size[0] / 2)
y = i / size[0] * fragment_size[1] + random.randrange(-fragment_size[1] / 2, fragment_size[1] / 2)
# print x, y
image_all.paste(im, (x, y), im)
return image_all

I try it like this, I know parameter n is tricky, it was the scale it thumbnail the large image. Maybe I’ll change it to something more clear later…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def main(filename, n, scale, iteration, path='./'):
# 0. select an big image for mosaic
print "open %s" % filename
im = Image.open(filename)
# 1. process image as png to support transparency
print "process directory %s" % path
process_directory(path)
# 2. get a dict for path
print "get tile dict for path `%s`" % path
try:
with open('dic.txt', 'r') as f:
dic = p.load(f)
except:
dic = tile_dict(path)
with open('dic.txt', 'wb') as f:
p.dump(dic, f)
# 3. thumbnail the big image for compare
print "thumbnail background for compare"
# n = 30 # 原始图片缩为多少分之一
# scale = 3 # 原始图片放大倍数
big_size = im.size[0] * scale, im.size[1] * scale
im_chao = Image.new('RGB', big_size, 0xffffff)
imb_t_size = thumbnail_background(im, n)
print "how may tiles: %d X %d" % imb_t_size
print 'number of iterations: %d' % iteration
for i in range(iteration):
print 'iteration: %d' % (i + 1)
# 4. get a list of smail image for mosaic
print "get pic list"
im_tiles = get_image_list(im, dic)
# 5. paste in chaos style
print "generate final image"
im_chao = paste_chaos(im_chao, im_tiles, imb_t_size)
return im_chao


if __name__ == '__main__':
im = main('../mm.jpg', 15, 5, 2)
im.save('../final3.png')
im.show()

Demo

Do you like it?

Demo

Can you see it?

Demo Download(45.8M)

More examples here(Chinese)

Thanks

My family, It supports me.Never let me down, never pour cold water, never scold for insignificance.

可视化人人好友关系


目录

  • toc
    {: toc}

R分析人人网好友推荐系统用python进行人人好友分析启发,完全用python的模块和方式实现了一遍,结果搞得好像一点也不Pythonic,倒好像有点继承了之前在lisp下养成的函数式风格……

作为菜鸟深知代码写得不怎么样,写在这里,希望没什么基础的人都能体会到其中我所感受到的乐趣Happy hacking,也欢迎各路高手大牛不吝赐教。

完整代码见github/reverland/scripts/renren.py

必要条件

For Reader:

读者需要有一定python基础,如果没有,不妨花半个小时看看Python简明教程

For Computer:

我在gentoo linux下完成所有的编写测试,也推荐想尝试的朋友选择linux环境。不过只是推荐,python作为著名的跨平台语言,其代码可以没什么差别的运行在各个平台上,但你需要以下一些必备的东西:

  • python 2.7 也许2.5也行,cookielib之前好像不在标准库中,而python3中则有改动。
  • networkx 一个分析,操作,绘制网络的python模块。
  • matplotlib 经常用来绘图的python模块

怎么安装请自行参照官方网站说明。对后两个模块,建议使用pip安装,这货就相当于个包管理器(一条命令完成搜索下载安装所有操作并自动处理所有依赖)。

最后,还有可选的开发环境:ipython,该程序提供一个功能强大的交互环境,很方便做测试调试探索各种 一次性 工作。

我们要做些什么

从人人网上抓取好友,绘制好友之间的关系图,还可以供进一步分析(貌似没什么好分析的)。

为了实现这点我们需要做到以下几个工作:

  • 模拟登录[^1]
  • 提取数据以合适数据结构保存
  • 制作图像并绘制

模拟登录

人人的模拟登录还是比较简单的。模拟登录最困难的部分就是对要登录网站登录过程的分析。通常办法是通过抓包,用wireshark总有种杀鸡用牛刀的感觉,而且当你像作者一样天天用socks代理时会发现什么也抓不到……所以IE/Chrome/Firefox的开发工具可能更合适。这里用firebug,你可以在火狐扩展中心找到并安装它。

人人登录分析

然后在抓包过程中找到用户名^2和登录时请求的服务器。

不过,之前有很多人已经分析过人人的登录过程(一般不会要求验证码,除非登录过于频繁)。你所必须要做的基本上只有两件事:

  • 将用户名和密码POST到服务器
  • 处理cookie

模拟登录的工具使用python的标准库中的urllib,urllib2cookielib即可

1
2
3
import urllib
import urllib2
import cookielib

如果对这三个标准库不熟悉,建议花时间看看下面两篇教程。不过也许无所谓,代码可以自己解释自己:p。

当浏览器使用POST方法请求服务器时,它将参数经过编码附加到url后传递过去:

http://www.renren.com/ajaxLogin/login&email=username&password=blablabla

登录成功后,还要获取人人中用来作为用户唯一标识额uid(打开人人主页注意url就看到了)并返回,以供将来使用。将来所有的抓取都通过独一无二的uid而非可能重名的姓名。

使用正则抓去uid

import re

我们先写登录函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def login(username, password):
"""log in and return uid"""
logpage = "http://www.renren.com/ajaxLogin/login"
data = {'email': username, 'password': password}
login_data = urllib.urlencode(data)
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)
res = opener.open(logpage, login_data)
print "Login now ..."
html = res.read()
#print html

# Get uid
print "Getting user id of you now"
res = urllib2.urlopen("http://www.renren.com/home")
html = res.read()
# print html
uid = re.search("'ruid':'(\d+)'", html).group(1)
# print uid
print "Login and got uid successfully"
return uid

不妨在ipython中先测试下。

抓取数据

每个人的好友都可以从页面http://friend.renren.com/GetFriendList.do?curpage=0&id=uid获取,虽然人人已经改版,但这个页面还能用。其中curpage参数的值是页码,id参数的值是拟抓取对象的用户ID。通过循环抓取所有好友并以用户id为键姓名为值保存为字典。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def getfriends(uid):
"""Get the uid's friends and return the dict with uid as key,name as value."""
print "Get %s 's friend list" % str(uid)
pagenum = 0
dict1 = {}
while True:
targetpage = "http://friend.renren.com/GetFriendList.do?curpage=" + str(pagenum) + "&id=" + str(uid)
res = urllib2.urlopen(targetpage)
html = res.read()

pattern = '<a href="http://www\.renren\.com/profile\.do\?id=(\d+)"><img src="[\S]*" alt="[\S]*[\s]\((.*)\)" />'

m = re.findall(pattern, html)
#print len(m)
if len(m) == 0:
break
for i in range(0, len(m)):
no = m[i][0]
uname = m[i][1]
#print uname, no
dict1[no] = uname
pagenum += 1
print "Got %s 's friends list successfully." % str(uid)
return dict1

我们再写个获取好友关系字典的函数,为了避免我们每次为了获取字典都要登录抓取。

1
2
3
4
5
6
7
8
9
10
def getdict(uid):
"""cache dict of uid in the disk."""
try:
with open(str(uid) + '.txt', 'r') as f:
dict_uid = p.load(f)
except:
with open(str(uid) + '.txt', 'w') as f:
p.dump(getfriends(uid), f)
dict_uid = getdict(uid)
return dict_uid

我们还需要一个用来判断两个人关系的函数,来判断我们好友之间的关系。

1
2
3
4
5
6
7
def getrelations(uid1, uid2):
"""receive two user id, If they are friends, return 1, otherwise 0."""
dict_uid1 = getdict(uid1)
if uid2 in dict_uid1:
return 1
else:
return 0

绘制图像

利用以上函数判断好友关系并通过networkx创建一个相应的网络。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def getgraph(username, password):
"""Get the Graph Object and return it.
You must specify a Chinese font such as `SimHei` in ~/.matplotlib/matplotlibrc"""

uid = login(username, password)
dict_root = getdict(uid) # Get root tree

G = nx.Graph() # Create a Graph object
for uid1, uname1 in dict_root.items():
# Encode Chinese characters for matplotlib **IMPORTANT**
# if you want to draw Chinese labels,
uname1 = unicode(uname1, 'utf8')
G.add_node(uname1)
for uid2, uname2 in dict_root.items():
uname2 = unicode(uname2, 'utf8')
# Not necessary for networkx
if uid2 == uid1:
continue
if getrelations(uid1, uid2):
G.add_edge(uname1, uname2)

return G

最后是绘图函数,有很多控制图像输出的参数,可能多次调整才会得到想要的图像。在matplotlib画出的图像在窗口中也可以放大缩小选取适当范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def draw_graph(username, password, filename='graph.txt', label_flag=True, remove_isolated=True, different_size=True, iso_level=10, node_size=40):
"""Reading data from file and draw the graph.If not exists, create the file and re-scratch data from net"""
print "Generating graph..."
try:
with open(filename, 'r') as f:
G = p.load(f)
except:
G = getgraph(username, password)
with open(filename, 'w') as f:
p.dump(G, f)
#nx.draw(G)
# Judge whether remove the isolated point from graph
if remove_isolated is True:
H = nx.empty_graph()
for SG in nx.connected_component_subgraphs(G):
if SG.number_of_nodes() > iso_level:
H = nx.union(SG, H)
G = H
# Ajust graph for better presentation
if different_size is True:
L = nx.degree(G)
G.dot_size = {}
for k, v in L.items():
G.dot_size[k] = v
node_size = [G.dot_size[v] * 10 for v in G]
pos = nx.spring_layout(G, iterations=50)
nx.draw_networkx_edges(G, pos, alpha=0.2)
nx.draw_networkx_nodes(G, pos, node_size=node_size, node_color='r', alpha=0.3)
# Judge whether shows label
if label_flag is True:
nx.draw_networkx_labels(G, pos, alpha=0.5)
#nx.draw_graphviz(G)
plt.show()

return G

把以上函数写进一个文件比如说renren.py,在ipython中导入。

1
2
3
4
5
6
7
In[1]: from renren import *

In[2]: username = yourusername

In[3]: password = yourpassword

In[4]: draw_graph(username, password)

模糊化生成的好友关系图

总结

通过图像你会发现。这些绘图软件的算法相当不错的,你会发现很明显的聚类,这一片是大学同学、这片是小学初中同学,旁边与之联系紧密的是高中同学,这一片孤立的是网友等等。

也许你还会发现你的某些好友竟然相互认识。

抓取下来的数据还可以留待其它研究

又是横竖坐标都没的渣图

你也许会发现有的好友和你的共同好友多得超乎他人,也许发现共同好友分布比较均匀

就这么多这么简单。

希望你也能体会到这个乐趣横生的过程,对我来说,探索和学习的过程是相当意趣盎然的,折腾出来还相当有成就感呢。

What’s more

如果你想让matplotlib显示中文,你需要修改matplotlibrc更改字体。但有一种更通用的办法可以不用修改配置文件。自行google。

ps:这回开高亮了,没感觉和不高亮有啥大区别。感觉还是vim中的高亮漂亮啊,哪天不用pygments直接用vim converto html = =

FootNotes

[^1]:从来没用过api,搞不懂人人api,试着创建个应用Post过去结果认证失败,也没打算申请应用……总之不会搞= =

Visualize Shell History

注:代码写得很烂,不过感觉挺好玩所以写在这里。欢迎各路大牛指教。完整代码见github/reverland/scripts/tagcloud.py

曾经在linux用户中流行这么一个命令

~ ⮀ history | awk '{CMD[$2]++;count++;} END { for (a in CMD )print CMD[ a ]" " CMD[ a ]/count*100 "% " a }' | grep -v "./" | column -c3 -s " " -t |sort -nr | nl | head -n20 
    1  852  24.3012%    sudo
    2  376  10.7245%    pacman
    3  163  4.64917%    vim
    4  133  3.7935%     tsocks
    5  101  2.88078%    cd
    6  95   2.70964%    kill
    7  88   2.50998%    eix
    8  70   1.99658%    python2
    9  70   1.99658%    emerge
    10  69   1.96805%    ls
    11  63   1.79692%    git
    12  54   1.54022%    gcc
    13  51   1.45465%    pip2
    14  39   1.11238%    python
    15  37   1.05533%    pip
    16  37   1.05533%    nmap
    17  35   0.998289%   su
    18  32   0.912721%   xrandr
    19  31   0.884199%   rvm
    20  27   0.770108%   ssh

多cool的一个命令……我完全看不懂awk啥的……几天前看The practice of computing using python,上面讲到简单的文本处理和标签云,便想到把shell history用标签云的方式可视化出来。就是这样,我啥也不会。

先把shell历史定向到一个文件中吧,或者把zsh_history啥复制下

history > hist.txt

然后如何可视化呢?抱着有需求先搜寻有没有开源实现的想法找到了pytagcloud,稍加调整,生成的标签云相当漂亮:

oops!好大两个“异常词”,这么说一看我就是sudo党了,而且是经常滚的arch党……

为了看清更多细节,反映更多客观事实把这两个词去掉

看上去好多了………

pytagcloud还提供生成html数据的函数,你可以在线看看效果:

Demo

自己动手

其实自己实现类似的效果很简单,获得更明晰的理解和灵活性。

先给出以下要用的控制大小的参数,后面将直接用到它们。你可能需要多次调整来探索适合自己的数值,事实上,为了生成不同文本的标签云我试过了几十次。

boxsize = 600
basescale = 10
fontScale = 0.5
omitnumber = 5
omitlen = 0

文本处理

我们刚才保存的hits文件是这样的:

2480  pacman -Ss synap
2481  sudo pacman -S synaptiks
2482  synaptiks
2483  pypy
2484  vim pypy.py
2485  pypy pypy.py
2486  pip2 freeze
2487  pip2 freeze|grep flask
2488  pip2 install Flask
2489  pip2 install --upgrade Flask 

显然我们只要每行第二个词就行,这个任务很简单,我选择先将所有命令合并成一个大字符串,因为最开始我是直接用pytagcloud来生成标签云的,而它的示例代码用的是整个字符串:

def cmd2string(filename):
    '''accept the filename and return the string of cmd'''
    chist = []

    # Open the file and store the history in chist
    with open(filename, 'r') as f:
        chist = f.readlines()
        # print chist

    for i in range(len(chist)):
        chist[i] = chist[i].split()
        chist[i] = chist[i][1]
    ss = ''
    for w in chist:
        if w != 'sudo' and w != 'pacman':
            ss = ss + ' ' + w

    return ss

接着将字符串转换成字典,单词为键,出现次数为值:

def string2dict(string, dic):
    """split a string into a dict record its frequent"""
    wl = string.split()
    for w in wl:
        if w == '\n':  # 因为后来我看到中文分词结果中有\n...
            continue
        if w not in dic:
            dic[w] = 1
        else:
            dic[w] += 1
    return dic

接下来的两个函数来自之前我提到的那本书,稍微改动下让它在firefox18下正常显示,并且稍作美化,更改为随机的字体色彩和黑色背景。

这两个函数的含义是不言自明的,必要的html/css知识是需要的。[^1]

def makeHTMLbox(body, width):
    """takes one long string of words and a width(px) then put them in an HTML box"""
    boxStr = """<div style=\"width: %spx;background-color: rgb(0, 0, 0);border: 1px grey solid;text-align: center; overflow: hidden;\">%s</div>
    """
    return boxStr % (str(width), body)


def makeHTMLword(body, fontsize):
    """take words and fontsize, and create an HTML word in that fontsize."""
    #num = str(random.randint(0,255))
    # return random color for every tags
    color = 'rgb(%s, %s, %s)' % (str(random.randint(0, 255)), str(random.randint(0, 255)), str(random.randint(0, 255)))
    # get the html data
    wordStr = '<span style=\"font-size:%spx;color:%s;float:left;\">%s</span>'
    return wordStr % (str(fontsize), color, body)

Now, it’s time to get the proper html files of the tag cloud!

# get the html data first
wd = {}
s = cmd2string(filename)
wd = string2dict(s, wd)
vkl = [(k, v) for k, v in wd.items() if v >= omitnumber and len(k) > omitlen]  # kick off less used cmd
words = ""
for w, c in vkl:
    words += makeHTMLword(w, int(c * fontScale + basescale))   
html = makeHTMLbox(words, boxsize)
# dump it to a file
with open(filename.split('.')[0] + '.' + 'html', 'wb') as f:
    f.write(html)

将以上内容写到一个文件中,命名为比如说tagcloud.py

python2 tagcloud.py hist.txt # `import sys` and let filename = sys.argv[1]
# or `run tagcloud.py hist.txt` in ipython

看看效果吧:

genkernelsystemctlnengo-cl./nengotsocksaxelnamcappidgingroupsemergefirefoxnmapvim/opt/nengo/nengocatmvhistorynengotargccdmesg|egrepmansupingmakepkglspythonrakermpkgfilenetstatechotopmkdirjohngvimpip2xrandrdfsshgemipython2ipythonmodprobeyou-getkdesuchmodcdcppslsmodeixmd5sumvimakepactreefc-list|grepgdbkillsourcelspcijekyllpython2exportwkhtmltopdfloginctlkatawa-shoujopkillgiteselectdebug-flvrvmpipequery

相当棒不是么?[^2]

十八大报告标签云

为了深刻领会党的十八大大会精神^3,我做了下我党的十八大报告标签云:

先从网上找到总书记的十八大报告全文,保存为shibada.txt:

中文分词有个相当不错的python库jieba

将单词保存到一个字典中

import jieba

with open('shibada.txt','r') as f:
    s = f.read()
wg = jieba.cut(s, cut_all=True)
wd = {}
for w in wg:
    if w not in wd:
        wd[w] = 1
    else:
        wd[w] += 1

生成html数据:

for w, c in vkl:
        words += makeHTMLword(w, int(c * fontScale + basescale))   
html = makeHTMLbox(words, boxsize)
htmlzh = unicode.encode(html,'UTF-8')  # Important!
# dump it to a file
with open(filename.split('.')[0] + '.' + 'html', 'wb') as f:
    f.write(htmlzh)
金融机构个人账户体制改革全党全国举世公认学前教育贸易组织管理网络精神食粮党外人士政企分开推进改革人民满意科学素养行动指南创建活动保护环境对外贸易党员干部充分发挥中小城市利用效率高度重视立于不败之地香港特别行政区资源整合社会制度科教兴国建立健全群众体育基本路线核心作用劳有所得腐败现象充满活力强权政治检察机关人大代表医药卫生居民消费各个环节坚持真理政治协商德智体美理想信念战略思想伸张正义组织协调思想道德两岸关系跨国公司腐败问题宏伟目标发展壮大不断扩大党风廉政共同富裕穷兵黩武根本宗旨管理科学急难险重医疗保障官僚主义严峻考验教师队伍保持稳定医疗卫生独立自主重大突破持久和平提高效益年龄结构合情合理妥善处置团结奋斗联系群众产业政策保险制度指导思想文化素质贫穷落后党员队伍依法行政睦邻友好各族人民巨大成就明显增强公共安全农民收入巩固国防恐怖主义主义精神主义教育执政为民机构编制妄自菲薄澳人治澳同舟共济群众反映基础产业经贸关系军事力量周边国家发展中国家综合国力求真务实批评和自社会效益民主监督马克思列安全事故事业单位建设工程改革开放土地增值解放思想产业结构违反纪律千辛万苦激励机制全面提高领导班子初级阶段出色完成自由贸易本质属性道德素质市场主体任人唯贤理论体系科学决策妇女儿童公立医院节能降耗人口老龄化贫困地区警钟长鸣坚定信心民主集中制创新能力日益增长时代特征经济体制国民经济气候变化教育引导成绩显著明显改善严惩不贷根本任务级计算机才尽其用党的建设法制建设党和人民基本国策基础设施严重困难预防为主基本原理养老保险面向世界国有经济政令畅通爱国卫生一律平等国际竞争社会保险自由贸易区腐败体系荣辱与共中型企业年轻干部互联互通五湖四海优秀人才伟大旗帜政策措施国家机关人人平等社会保障共同愿望始终不渝妥善处理深化改革综合治理祖国统一国际形势勇于创新现代农业勤俭节约民主党派统筹规划稳步前进价值体系群众意见中华文化长期实践集体主义山清水秀任务艰巨党的领导澳门特别行政区常住人口发展党员亿万人民团结互助人力资源矿产资源百花齐放引咎辞职中国共产党工作人员物质基础收入水平东北地区革命军人诉诸武力服务设施统一战线严格执法执法必严主要矛盾上层建筑分配制度优良传统结构调整全党同志退休干部政府职能百家争鸣波澜壮阔服务大局社会治安公平正义坚强有力不失时机坚持不懈公共卫生根本保证金融危机充分调动五项原则与时俱进非公有制食品药品党政领导面向未来高新技术民族团结民主制度素质教育繁荣富强恶化趋势小康社会义务教育以言代法争取和平社会福利技术创新常抓不懈经济总量和平时期服务水平扎扎实实前所未有下有对策优秀干部法定程序民主决策伟大胜利安居乐业各界人士公共财政共同奋斗空间结构纪检监察差额选举血脉相连城乡规划首创精神管理机制简政放权身心健康社会安定各尽所能家庭财产路线教育代表大会少数民族政权机关紧密结合人口素质热点问题一心一意违法犯罪大力发展贯彻落实人与自然十分艰巨教育资源感天动地水土流失谦虚谨慎信息技术形式主义公共服务海洋权益能源安全舆论监督集体经济意识形态考核办法决策程序正反两方时代精神内政外交廉政建设进一步提高严格执行武器装备历史使命经济命脉列宁主义总体布局子孙后代精神实质历史进程革命先烈社会变革和平解决创先争优积极支持再生能源从根本上自我教育教书育人坚定信念无党派人士人民代表品德教育优先发展劳动生产率规模经营以人为本领土完整基层组织立党为公自然灾害一如既往坚定不移改旗易帜国家主权领导职务加强监督公益事业医疗保险生产总值海外侨胞积极向上经营机制艰苦奋斗重中之重有用之才新闻出版民主评议不良风气社区卫生军事训练台湾同胞可持续性多种形式丰富多彩必然选择自然生态防御能力经济基础重大成就和睦相处人口比例民族特色努力实现科学研究全面实施正当权益组织生活十国集团承包经营国防建设合法收入文化产业明显提高武装警察知识分子相信群众扶贫开发社会阶层妥善解决自我批评金融体系不断丰富取长补短劳动所得全国代表大会一府两院脱离群众分配比例提高质量工作力度惩治腐败美好世界始终保持工人阶级城乡居民高度一致社会公德技术产业金融监管政治文明国际争端党纪国法遵守纪律宏观调控产权保护组成部分深入开展生态效益广大青年老有所养戒骄戒躁弱肉强食团结合作超级计算机消化吸收和衷共济行政长官有利条件兢兢业业精神力量攻坚克难在思想上长治久安人人有责文化交流职业道德同心同德对外开放国民收入关键在于加以解决教育方针国有资本不断加强宏观经济不可逆转审判机关生命财产万众一心千方百计生产关系广泛开展干部队伍矢志不渝国有企业内忧外患公民道德高度自治权面向基层友好往来合法权益功能定位没有特权战略方针网络空间能进能出人民调解社会主义伟大工程议事规则外交政策三个代表人才培养居民收入伟大事业集中统一中央政府军事战略科技进步新民主主义埋头苦干德才兼备特殊教育产品质量居安思危马克思列宁主义民主协商精神文明福利制度正确方向步调一致爱国人士信息系统徇私枉法绝不允许长效机制低收入者充满希望港人治港特殊人群正确处理慈善事业北京奥运工资制度发达国家参政议政党的基本民主选举妄自尊大积极主动政治立场全面落实方针政策市场规律严峻形势毫不动摇经济效益节约资源科学知识尊重人才突出位置群众利益和平共处人民团体认真总结环境污染力量对比路线方针中共中央统筹兼顾法制宣传马克思主义霸权主义新民主主义革命有令不行有禁不止地方党委基本纲领后备力量安全监管正确认识集中精力新民主主党和政府选拔干部公正司法文学艺术管理体系自我表现全心全意邓小平理论一国两制环境友好当今世界第十七届合理配置收益分配奋发有为管理体制集中体现领导核心大是大非管理制度民间团体退役军人社会科学化解矛盾生活空间国际事务调整机制当家作主贴近生活服务体系积贫积弱军民团结人民军队信息网络五位一体病有所医战略规划中央委员会生产能力和谐社会根本利益衣食住行商业模式清醒认识实事求是男女平等能源消耗科学合理按劳分配依靠人民切身利益紧紧抓住共同努力违法必究整体实力中央委员水利建设生态系统优化结构相互交织实际行动总揽全局税收制度提高素质人事制度市场竞争明确提出积极开展决不允许依法治国干涉主义共同理想敌对势力非法收入中华儿女局部战争干部人事奢侈浪费突发事件经济社会组织体制保障体系切实有效行政区划奋勇前进伙伴关系流动人口国防科技开发利用公共事务外部环境职工代表中华民族坚实基础清正廉洁保障制度前进方向反腐倡廉充分证明人均收入经验教训根本途径不败之地依靠群众现实意义积极参与共同利益杰出贡献上有政策民主集中互相监督群众路线职业技能共产主义和平统一新形势下九十多年十分复杂党和国家是非曲直关键环节统一大业产品价格仁人志士精神家园领导集体突如其来新兴产业重大进展自我完善犯罪活动一以贯之风云变幻勇于进取全面实现资源节约型忧患意识高速铁路信息安全内部矛盾青年工人户籍制度深入人心逐步完善广大党员问政于民二氧化碳政治体制社会风尚五千多年传统产业三十多年廉政文化模范作用民主主义有法必依自我管理损害赔偿幸福美好坚决贯彻时代特色国际金融严格控制自觉遵守文明执法建言献策财政收入基本保障拒腐防变永无止境宣传教育健康成长民主权利卫生事件聚精会神党政干部计划生育重大胜利长期共存生活富裕循序渐进求同存异主义理论分配机制增强党性成效显著粮食安全民主法制立于不败软弱涣散大案要案优势互补教育领域保护主义民族之林基本国情奋发进取世界贸易组织肝胆相照多党合作毛泽东思想行使权力前沿技术不懈努力海洋资源投机钻营者知识产权友好合作人才资源顽强拼搏人类文明利益冲突物质文明科学规范良好环境社区服务尊重知识第十八次市场调节民族区域思想观念市场经济公共资源大有作为赔偿制度从严治党爱国主义作出贡献科技体制合理安排基本方针规模宏大放在首位扫黄打非人民政协积极响应高级干部艰苦卓绝传统美德资源管理精神支柱金融体制劳动报酬精神状态标本兼治利用外资边疆地区语言文字终身教育爱国统一战线服务网络党的纪律资源配置各得其所充分体现阔步前进人民代表大会生产方式开展批评安置工作扩大内需必由之路国际局势此时此刻共产党人合理布局生态环境环境保护发展前景网络安全亡党亡国政法队伍人才队伍健身运动

嗯……深刻领会了十八大精神^4

What’s more

可以将标签云移植到博客上。

Footnotes

[^1]:抱歉……我忘记python怎么将长行划分了\ or \\?
[^2]:emerge 乱入……

基于开源工具的数据分析

书的图片

这是书评,不仅仅是书评。事实上,这本书我还没看完。考研之前大概两个月时偶然在图书馆外文图书阴暗的角落发现了这本书,然后考研复习平常上课都被我扔了,连续一周徜徉在数学和计算机的世界里。再往后?大概到十四还是十五章被迫准备研究生入学考试去,直到现在还没拾起来。

后来在一楼看到有中文图书,感觉翻译的不错,起码比我自己理解的好。就换了本中文的带回家来看。

废话很多?不是么?好吧这篇书评和书的内容没什么大的关联,满篇只因为我又想 胡扯 了。

Amazon上对这本书的评价:Very Insight。Too insight 以致于我真想跑跑题。

系统与文化

从书上的一个故事说起。作者建议数据分析工作人员和科学家用Unix系统工作,为此专门举了个例子:

True story: I needed to send a file containing several millions of keys to a coworker.(The company did not work on Unix.) Since the file was too large to fit safely into an email message, I posted it to a web server on my desktop and sent my coworker the link. (I dutifully had provided the file with the extension .txt, so that he would be able to open it.) Five minutes later, he calls me back: “I can’t open that”—“What do you mean?”—“Well, I click the link, but ScrapPaper [the default text editor for small text files on this particular system] dies because the file is too big.” This coworker was not inept (in fact, he was quite good at his primary job), but he displayed the particular non-problem-solving attitude that develops in predefined work environments: “Link, click.” It did not even occur to him to think of something else to try. That’s a problem!

就在昨天,看到行者无疆上对百度的公司的风格很是一顿猛批:其为员工预装的系统还是十年前的windows XP,天天用着盗版SecureCRT和Office软件工作。问题是:This matters?

我觉得重要!关键在习惯和文化上!

看看作者如何谈论:

Unix was developed for precisely this kind of ad hoc programming with files
and data, and it continues to provide the most liberating environment for such work.
Unix (and its variants, including Linux and Mac OS X) has some obvious technical
advantages, but its most important property in the present context is that it encourages
you to devise solutions. It does not try (or pretend) to do the job for you, but it goes out of
its way to give you tools that you might find handy—without prescribing how or for
what you use them. In contrast, other operating systems tend to encourage you to stay
within the boundaries of certain familiar activity patterns—which does not encourage
the development of your problem-solving abilities (or, more importantly, your
problem-solving attitudes).

关键就在这里,Unix系统 encourages you to devise solutions, 它不尝试为你做完所有事,但是它竭尽所能为你提供各种各样的工具和选择,而不是规定使用的方式和用途。而其它操作系统往往鼓励你留在习惯的活动模式范围内——毫不鼓励你提高解决问题的能力,更重要的是,解决问题的态度!

这也就是为什么,Linux、Mac OS和BSD这些Unix系统被称作黑客^1的操作系统,而Windows一直饱受诟病,在geek的群体中备受歧视。

从开始接触Linux到现在不到一年半,按理说作为一个noob没什么评头论足的资格,但这一年半却是改变我人生轨迹的一年半,我想分享出来自己的想法和折腾。也为了印证为何我也这么说这么想。

从自己说起

一年半时间,世界和自我完全变了。

折腾的苦与乐,爱与恨,交织纷繁。

也许当初真的太闲了才会一脚踏进这个无底洞,不过,who cares。就说说这个系统和文化如何影响、塑造了我。

故事从SAS开始,一款统计软件。当时数学建模用着盗版的SAS,老师说,这个正版太贵,我们买不起。

问题是有多贵?我开始上百度^2找答案,听说的答案是:一年几十万。

The price shocked me,从来没想过一个软件会这么贵。缘分就在这里,看到有人在推荐R(A powerful statistics environment)作为替代。这是我第一次听说开源,也是我折腾的开始,踏入新天地的开端。

没体会过的人永远不会理解我为什么说新天地,也不会理解这有什么好感慨的。

我从来没想过将来去从事什么计算机相关的工作,从来。从来觉得数学这东西一无是处,都是空谈。从来觉得世界分工很多事情自己都不该去接触去学习。从来以为世界就是自己身边这么大。从来觉得一生这么混混就过去了。

但一年半后我再也不这样想了。依然迷茫,然而有信心。

这一年半我觉得做了许多让自己骄傲的事,最起码没有虚度。虽然在别人眼里我碌碌无为,甚至一无是处。我依然相信、我的所有努力和折腾不会白费。就像Jobs当在Stanford演讲所说[^3]。

一分耕耘、一分收获。

为什么会折腾?和系统有关系吗?

有!文化。有些环境不鼓励探索和设计解决问题,而是鼓励你混日子。

关于开源社区的文化,我想说几条:

热情

大多数人都只因热爱。开源社区是充满热情与爱的社区,开源本身就是个奇迹。你会想到有人无偿将自己的劳动成果贡献出来让所有人都能自由获取和使用吗?然而不光有人做,还有一群人做。他们把技术、心得分享出来,让每个想学习的人都平等的接触他们。他们花费宝贵时间写出组织良好充满热情的文档、教程,录制视频,他们花费宝贵的时间本地化各种应用,在IRC和论坛等地热情帮助他人。他们也做出各种各样的艺术品。

分享

开源社区的分享氛围真是太好了。我为什么倾向于使用Python,因为它本身就是依靠开源发展壮大起来,深受开源文化陶冶的语言。来自各个领域、各个地区的爱好者们开发了各种各样的库分享出来让每个人都能自由获取,以致于很多事情用Python太简单了。数以万计的开源软件使用者在互联网上分享、反馈、改进他们喜欢的东西。这种文化也构成了互联网的分享基础。

好奇心

正如本书作者在前言中所说:

All You need is just CURIOSITY!

开源社区给了每个人自由平等接触学习的机会,你所需要的仅仅是好奇心。从接触linux开始,我在上面折腾过各种数学软件R、octave、scilab、ipython(其实这不是……)、各种风格和特色语言[^4]、自己学习图像处理的基础知识和使用图像处理软件(如果时间很多就去学blender)[^5]、自己学习字体排版的理论折腾LaTeX、自己试着零基础折腾各种动静态网站、在虚拟机上装好各种linux/windows系统然后连着玩……虽然没学到什么或者学过也忘了或者不深入,但学到的是解决问题的态度和能力,这才是我觉得最重要的。时光飞逝,一切都会过时变化,重要的是面对问题的态度和解决问题的能力。

开源的文化改变了我的思想、行动,开阔了我的眼界,我觉得这对每个人都是有益的。剩下的,就是你愿不愿意付出“代价”来改变自己了。

开放的社区欢迎任何人投入其中、分享、学习、进步,接触和尝试各个领域,你也许对计算机知之甚少,对数学一窍不通,但行业的鸿沟真的这么明显吗?难而不会、会而不难,你会找到很多开放的社区有热情的人分享的资料文章、看到清晰热情的文档、在论坛IRC等获得热心的帮助。

不妨试试,你会爱上这种文化。

最后顺便说下,开源社区创造了很多很棒的东西,越是重要的东西越默默无闻,然而不可或缺。

Footnotes

[^3]:Follow U heart.
[^4]:其实很少,我认真学的第一门语言是common lisp。
[^5]:有兴趣的同学可以去看看Tears of Steel,这是blender、gimp、Inkscape等开源多媒体软件制作的。

警告:渣行文,就是想到什么扯什么……散漫不羁,漫无主题。

注:你也许可以把这篇极水的流水帐当作 Tentative Instruction for gentoo on Samsung R429 不过我写这篇文章的目的在于自我警戒与警戒他人,一次gentoo安装让本屌丝sb本质暴露无疑,诸位看官引以为戒。

机器信息

Cpu信息,这就是传说中的i3 XD

⚡ root@gentoo ⮀ ~ ⮀ lscpu 
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    2
Core(s) per socket:    2
Socket(s):             1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 37
Stepping:              2
CPU MHz:               2266.000
BogoMIPS:              4521.96
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              3072K

硬件:

⚡ root@gentoo ⮀ ~ ⮀ lspci
00:00.0 Host bridge: Intel Corporation Core Processor DRAM Controller (rev 12)
00:01.0 PCI bridge: Intel Corporation Core Processor PCI Express x16 Root Port (rev 12)
00:1a.0 USB controller: Intel Corporation 5 Series/3400 Series Chipset USB2 Enhanced Host Controller (rev 06)
00:1b.0 Audio device: Intel Corporation 5 Series/3400 Series Chipset High Definition Audio (rev 06)
00:1c.0 PCI bridge: Intel Corporation 5 Series/3400 Series Chipset PCI Express Root Port 1 (rev 06)
00:1c.2 PCI bridge: Intel Corporation 5 Series/3400 Series Chipset PCI Express Root Port 3 (rev 06)
00:1c.3 PCI bridge: Intel Corporation 5 Series/3400 Series Chipset PCI Express Root Port 4 (rev 06)
00:1d.0 USB controller: Intel Corporation 5 Series/3400 Series Chipset USB2 Enhanced Host Controller (rev 06)
00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev a6)
00:1f.0 ISA bridge: Intel Corporation Mobile 5 Series Chipset LPC Interface Controller (rev 06)
00:1f.2 SATA controller: Intel Corporation 5 Series/3400 Series Chipset 4 port SATA AHCI Controller (rev 06)
00:1f.3 SMBus: Intel Corporation 5 Series/3400 Series Chipset SMBus Controller (rev 06)
02:00.0 VGA compatible controller: NVIDIA Corporation GT218 [GeForce 310M] (rev a2)
02:00.1 Audio device: NVIDIA Corporation High Definition Audio Controller (rev a1)
03:00.0 Network controller: Atheros Communications Inc. AR9285 Wireless Network Adapter (PCI-Express) (rev 01)
07:00.0 Ethernet controller: Marvell Technology Group Ltd. Yukon Optima 88E8059 [PCIe Gigabit Ethernet Controller with AVB] (rev 11)
3f:00.0 Host bridge: Intel Corporation Core Processor QuickPath Architecture Generic Non-core Registers (rev 02)
3f:00.1 Host bridge: Intel Corporation Core Processor QuickPath Architecture System Address Decoder (rev 02)
3f:02.0 Host bridge: Intel Corporation Core Processor QPI Link 0 (rev 02)
3f:02.1 Host bridge: Intel Corporation Core Processor QPI Physical 0 (rev 02)
3f:02.2 Host bridge: Intel Corporation Core Processor Reserved (rev 02)
3f:02.3 Host bridge: Intel Corporation Core Processor Reserved (rev 02)

:s/arch/gentoo/gc

2013年一月十三日,开始装gentoo。依照The Gentoo Linux alternative installation method HOWTO从BT5 R3的liveusb来chroot过去部署的stage3。一年多linux使用的结果是,chroot轻车熟路,archwiki中chroot那章还是我翻译的呢,不过……渣翻译。

没什么理由,甚至对arch相当满意。然后就顺手给//boot干掉了……单独分区天然优势,不用折腾什么lvm就能大胆的乱搞……

Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *          63      208844      104391   83  Linux
/dev/sda2          208845     4417874     2104515   82  Linux swap / Solaris
/dev/sda3         4417875    65866499    30724312+  83  Linux
/dev/sda4        65866500   625137344   279635422+  83  Linux

引导

这是这次安装和配置gentoo时犯的第一次sb……

当时内核编译好。手册上的示例是grub和lilo做引导,而我习惯syslinux。素来以尊重用户选择为指引的gentoo在手册上就是没提及半点syslinux,而在arch下的操作又不一样。于是找到gentoo的syslinux的wiki。按wiki步骤写了自己的extlinux.conf:

TIMEOUT 30
ONTIMEOUT gentoo

UI vesamenu.c32
MENU TITLE Boot

LABEL gentoo
MENU LABEL Gentoo Linux
KERNEL /boot/kernel-genkernel-x86_64-3.6.11-gentoo
APPEND initrd=/boot/initramfs-genkernel-x86_64-3.6.11-gentoo root=/dev/sda3 acpi_osi=Linux acpi_backlight=vendor

然后重启……无法载入root,进入某个rescue shell内,什么神shell什么命令都没用。

冷关机chroot,查找资料改以上配置文件n次,重装extlinux又n次,重启n次,依然无解。然后忽然发现……extlinux的配置文件是extlinux.conf,而不像syslinux,pxelinux和isolinux那样都是.cfg,瞬间知道自己sb了……

图形界面

然后还算顺利吧,开源驱动编译了好久,emerge不会用,我是什么都:

emerge --autounmask-write foo
dispatch-conf
u
emerge foo

奇葩的是我想到什么emerge什么……于是搞了好久都没有图形界面用……

搞了个xterm+luit+telnet上听雨……发现字体显示不全……和听雨技术blabla的用英语开始版聊,然后十大了……囧

为了能一边上网水贴吧,一边编译系统。第二天回到BT5的liveusb环境中去了,又把自己喜欢的东西先emerge出来了……图形界面还没起来把gimp和vlc就编译好了……

等开源驱动装好,kdebase-startkde装好之后,重liveusb环境重启,擦……奇葩的分辨率……然后又开始查怎么调分辨率。

然后从开源到闭源,发现闭源不能调亮度,再加上没有kms很不爽,又转到开源。对这款机器来说,估计nvidia-bl驱动你也可以调亮度,不过我没试过。我只是把闭源驱动生成的xorg.conf改了改扔给了开源驱动^3

 ⚡ root@gentoo ⮀ ~ ⮀ cat /etc/X11/xorg.conf 
# nvidia-xconfig: X configuration file generated by nvidia-xconfig
# nvidia-xconfig:  version 304.64  (buildmeister@swio-display-x86-rhel47-12)  Tue Oct 30 12:04:46 PDT 2012


Section "ServerLayout"
    Identifier     "Layout0"
    Screen      0  "Screen0" 0 0
    InputDevice    "Keyboard0" "CoreKeyboard"
    InputDevice    "Mouse0" "CorePointer"
EndSection

Section "Files"
EndSection

Section "InputDevice"

    # generated from data in "/etc/conf.d/gpm"
    Identifier     "Mouse0"
    Driver         "mouse"
    Option         "Protocol"
    Option         "Device" "/dev/input/mice"
    Option         "Emulate3Buttons" "no"
    Option         "ZAxisMapping" "4 5"
EndSection

Section "InputDevice"

    # generated from default
    Identifier     "Keyboard0"
    Driver         "kbd"
EndSection

Section "Monitor"
    Identifier     "Monitor0"
    Modeline "1368x768_60.00"   85.25  1368 1440 1576 1784  768 771 781 798 -hsync +vsync
    Option         "DPMS"
    Option         "PreferredMode"  "1368x768_60.00"
EndSection

Section "Device"
    Identifier     "Device0"
    Driver         "nouveau"
    Option         "NoLogo" "true"
    Option         "RegistryDwords" "EnableBrightnessControl=1"
    VendorName     "NVIDIA Corporation"
EndSection

Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
    SubSection     "Display"
        Modes      "1366x768"
        Depth       24
    EndSubSection
EndSection

想知道modeline怎么写的?请man cvt

总之,这么一搞,开源驱动有这款机器的分辨率了。

这部分最后补充下我犯的第二次sb,chroot过去忘了date到正确的时间,结果早上开始emerge kdebase-startkde 晚上发现它还在等着在多少多少秒之后的未来某时开始编译……于是水了一天贴吧发现什么都没干。

后安装时代

第三次sb在于,妄图打造一个纯正的无gtk环境,

  • 把gvim的gtk参数去掉了,靠……对着wx的gvim渣界面我还奇怪怎么这么难看。
  • 把fcitx的gtk参数去掉了,然后奇怪firefox中怎么输入不了……
  • 最后吧,选择kde环境我觉得本身就挺sb……bug要不要多了点……当你想要美化kde环境下不堪入目的gtk程序而选择安装Oxygen-gtk后,却发现Oxygen-gtk的widget出现不了时你可以参看参看这里。一般情况下,你如果碰到这个问题,说明你要么是升级kde,要么是家目录有一堆以前的配置。

引导出错?

从W城到X城,十个小时的火车,又犯了一次sb。以为早上六点到X城,半夜两点乘务员把我叫起来说到站了,迷迷糊糊的出站四野一片大雾。晕头转向地走进KFC打开电脑等天亮……草……启动不了了。然后我chroot重编译内核检查硬盘内存一直搞到没电。

等到回家,忽然想起光驱里放了个没用的光盘……

Home

回家开始拨号联网,怀念arch下Networkmanager无往不利,按wiki编译设置好。先是发现没无线网络,然后dsl拨号连不上。

这是第几次sb来着……查找N多资料,编译N次内核,n次networkmanager,甚至试了试wicd,最后发现用户名写错了……卧槽啊……

无线内核也是个大坑,gentoo安装手册上说:

Be aware though, as genkernel compiles a kernel that supports almost all hardware, this compilation will take quite a while to finish!

还说:

This means that when you use genkernel to build your kernel, your system will generally detect all your hardware at boot-time, just like our Installation CD does.

于是我sb的以为会生成个和ubuntu或arch一样的通用内核,实际上竟然不完全是。^1不知道是chroot原因还是什么,RTC支持没有编译(hwclock),无线网卡驱动没有编译(ath9k),如果你要用vbox,这个支持也要编译上(iommu)。

我觉得最sb的在于,我以为genkernel会自动读取当前目录的配置……各位看官引以为戒,使用软件前认真看手册,不要自以为是

好了最后没什么了,一个libreoffice编译了五个小时,添加了gentoo-zh和sunrise的overlay。装上了katawa-shoujo,64位gentoo跑32位程序全无压力,连pulse-audio都不用就有声音(arch下为了发出声音必然的依赖)……

然后……就是开虚拟机写毕业设计开题报告的事了。囧……

附录

附录一——截图秀

这是秀gvim和gentoo的logo:

秀gvim的powerline

秀zsh的powerline

yakuake and zsh powerline

这是秀oxygen主题,金属光泽和性感的阴影。

日用无碍

附录二——工作清单

终于可以使用中文了。截止

Sun 13 Jan 2013 12:52:51 AM CST

已完成的工作

[X] vlc

[X] gimp

[X] luit/telnet 上听雨

[X] w3m

[X] nouveau

[X] zsh

[X] wqy-zenhei wqy-microhei

[X] ipython pip (python2)

[X] firefox-bin18

[X] startkde(去除bluez,我没有蓝牙适配器)

[X] ppp,dhcpcd

[X] 通用内核

[X] syslinux

[X] 较低版本的fcitx

[X] layman添加gentoo-zh, 安装git和subversion。

[X] xinit

还有些问题:Mon 14 Jan 2013 12:27:09 AM CST修正

[X] 分辨率低,不能设置为1366x768,换闭源驱动可解决

[C] gentoo的stageball难道给我装了一堆开发工具?sandbox pyshell pycrust pyalamode?

[X] gvim显示好难看,而且输入法不能起作用,gtk选项

[X] oxygen还要单独安装么?bug,重编译解决

[X] 缺少声卡驱动?还是alsa?声音调节。alsa

[X] 触摸板不起作用。synaptics

[X] 亮度无法调节(kde电源管理工具,and powermanage)开源可以闭源不行,acpid acpi Option依然无力[^4]

[X] dolphin,okular,gwenview等常用工具没装

[X] sudo sudoer文件写法

[X]用户组处理

[]摄像头

[X]如果开源驱动,开启kms

[C]change to nvidiabl

Others:

[X] kdm

[X] vbox安装、配置

[X] 重新编译firefox18,而不是bin

[X] oh-my-zsh 换上有非常漂亮powerline的agnoster主题,上图

[C] overlay 更换现有输入法?注意ICU,暂时不更改了

[X] 片轮少女^2

[X] 是否换闭源驱动 是 logo去掉

[X] virtualenv,pip

[C] gcc暂时不升级

幸运的是,家目录没有变动。所有的用户配置都在,如vim,kde,甚至rvm都能正常使用。

Mon 14 Jan 2013 12:30:54 AM CST

除此之外我还做了什么:

[O]恼人的zsh下sudo自动补全。sudo没解决(把配置复制给root了都没用)

[X]精简内核,被genkernel坑了,原来它不会自动读配置

[X]latex编译,ctex字体配置

[X]无线网内核支持编译ath9k

[X]Networkmanager的dsl拨号无法使用

[X]unzip,unrar,zip(natspec标记)

[X]hwclock 内核RTC支持

Sun 03 Mar 2013 11:47:18 AM CST

[X]重新配置内核,添加摄像头支持

附录三——经验教训

  • sb一样上来emerge vim…openbox+xterm听雨都显示不了汉字.So,先打造个可以上网的环境再说
  • chroot是个不错的选择,但不仅要挂载proc等[参见alternative’],还要date…
  • emerge使用,portage的理解,use 标记 the heart of gentoo.
  • 显卡驱动是个蛋疼的事
  • firefox编译时直接卡爆,不过最后还是编译好了
  • gvim和fcitx要加上gtk选项,不然gvim就一个默认的wx界面,fcitx无法在gtk程序中使用
  • 非系统级python模块使用virtualenv+pip

Footnotes

[^4]: 后来发现acpi没用,powerdevil就够用了。另为唤醒后亮度失控的问题找到解决方法了arch的wiki,在内核启动行加上acpi_osi=Linux acpi_backlight=vendor

警告:以下内容建议别看,保护好节操和三观

The way a crow

Shook down on me

The dust of snow

From a hemlock tree

Has given my heart

A change of mood

And saved some part

Of a day I had rued.

两天前在吴都路景观道上一个人走着,飘落的大雪和忽然鸣叫的乌鸦,那时那刻的情境与即将考研结束的欣喜心情,这首诗好像水到渠成似的被忆起,美丽的诗句长久地回荡在心中。

即将从大雪滚蛋的欣喜与对景物朋友的怀念感伤,即将了却一段心事的轻松与名对不可知的未来的紧张,对舍我其谁的自信与琢磨不清无法战胜的自卑,欲闯荡天涯的决心与对家人的眷恋与羁绊,万千情愫,在万籁俱静的夜里,在惨惨淡淡的昏黄路灯下如满天飞雪一般交织,模糊,空灵而渺远。感觉好像要融化在无边无尽的夜中,失去自我与世界的界限。


目录

  • toc
    {: toc}

总结2012

概述

  • 一年时间,试着更懂自己,试着追寻自己都不知道的梦。凄凄惨惨一个人的折腾。
  • 半年时间,在家的时间只有半个月,家是永远不能忘却之痛,不能隔断的羁绊。
  • 四个月时间,准备考研去帝都一所从未去过,之前从没想过的大学。只因为,莫名其妙的上了byr的linux版。

这一年,在考研与工作的矛盾,折腾实践与看书学习的矛盾,无限折腾与身体保养与锻炼之间的矛盾、极端反娱乐和身处娱乐大环境的矛盾、实践过程积累的自信和面对前途无力的自卑之间的矛盾、趋独和谋求与他人合作之间的矛盾,本专业渐进转型和彻底决绝地跨专业的矛盾的运动中不断前进上升。每个阶段主要矛盾都不同,而每个矛盾在不同的历史阶段作用和影响也不同。

这一年,是积极进步的一年,是不断学习与自我完善的一年,是不断促进自我与世界和谐的一年,是不断思索求生存谋发展的一年,也是充满曲折道路,探索光明前途的一年。这是一路蹒跚前进充满着血的教训的一年,然而我还没挂!!这是积累了我终生受用的宝贵经验的一年。

我做了什么

带着些许的狂热开源精神进入2012,继续进行漫无目的的折腾。

网站

一月二十八号看到Phoenix在ubuntu中文论坛教怎么申请免费域名免费空间建立一个wordpress空间。然后在家折腾了一晚上,建立了我的第一个wordpress网站。建立个人分享网站的愿望几个月前就深植心中了,漫无目的的尝试了n次。这是第一次成功实践。但免费网站空间非常之慢。

不久之后又看到丘迟的维基世界,又搜到好几个vimwiki建立的个人网站,然后抱着试试看的心理试了下ruchee的css,接着开始深入用vimwiki建站。

vimwiki建立的静态站点开始放在免费空间上,现在还在http://reverland.cu.cc/,后来改版后放在github上,最后迁移到bitbucketreverland.bitbucket.org。在这里赫然列着我自己都懒得去看的从二月某日到四月某日每天的日记,无边的折腾笔记。

其实丘迟的网站很早就看到了,一直不知道他在讲什么,只感觉很牛逼……随着实践-认识-再实践-再认识,我才不断理解和能动地改造出符合自己实际需求相结合的个人网站。

直到某日又看到soimort天花乱坠的jekyll网站,我一激动就迁移到jekyll了

其实jekyll和Octopress在2011年就听说了,可是一直懒得迁移。当时什么也看不懂,折腾失败……

之后大半年,除了tk域名连个邮件提醒都没的被收回,从Phoenix入手域名外,一直稳定维护jekyll网站。

忘记什么时候了,懒得折腾前端页面啥的,看到skydark非常漂亮功能全面的博客,直接 剽窃 来了,然后换了个twitter bootstrap的主题。

之后偶尔零星收到有关评论和感谢信都是很开心的。

翻译

计算机语言

  • perl和R,在新的一年到来前就忘得一干二净。

  • 偶尔用用bash

  • LaTeX,如果这算语言的吧,珍爱生命,远离排版。2012年除了写了几次作业再没用过,即使用也是用模板。还尝试了一次lyx。

  • Common Lisp,受liutos热情影响,掉进这个大坑了,然后把land of lisp看完了,看完的第一本原版书。读书笔记点此

  • html和css,折腾网站你不得不学的东西。

  • Python,最熟悉的语言了,模块和库太方便了,相比lisp而言。看了一阵《python与科学计算》。

  • cpp,大学的酱油课,差点挂掉。

  • 一点点scheme,纯粹之美。

数学

  • 高数的复习,打下坚实数学基础

  • 基于开源工具的数据分析。某次去图书馆不小心看到了,然后什么考研直接被我扔掉了。不过后来才看到有中文版。江南大学图书馆有本影印版,现在还在我手里,有本中文版,不知道有人借走了没。

  • 一些数学建模时的东西、机器学习算法、概率论与数理统计知识。

图像处理

看了部分gimp手册和在翻译scipy-lecture-notes时积累了些色彩理论和图像处理方面的基础。然后随便折腾了些。

考研复习

专业课信号与系统,感觉学了不少东西,纯数学。

政治学习,现在说话办事满脑子马克思主义观点立场方法,一讲话一套一套的……

打好了数学基础

创新项目

几天前论文发了,算是彻底的结束了。趁着学习实践了好多东西,还用了半年的免费网络。总结见此

其它

大学混了一年,对这屌地方提不起一点兴趣,甚至感觉碍手碍脚。不过学校很多方面就是好啊。混得最后的课差点挂掉。

严重的独立倾向,疏于与同学朋友交流联系,共同学习和进步。

学会了一边唱最炫民族风一边马步舞 和 八九十套广播体操。

无边无尽的水论坛和贴吧,byr,baidu linux吧,archlinux吧是我的常驻。话说byr上我的发帖都上千了,贴吧不到一年9级……

其它,如果还有什么特别重要的?


展望2013

一些事情和要注意的地方。

三件事

毕设

  • 早上去毕业设计导师那里把题目定了下来。导师没有为难我,最后完全选了一个图像处理的彻底跨专业的毕业设计。算是遂心如愿了,反正我希望能做点什么并学到很多。

工作

  • 之前感觉跨专业找工作无望,悲情之下无奈考研。后来看到知乎发在豆瓣python小组的招聘,瞬间就想找工作了……不过过了几天知乎的工作要求又改了。但起码,让我觉得,至少找个实习全无压力。即使研究生考试无望,也想过完年到北京找实习。( 最好 年前准备)。

考研

  • 复试科目,概率论与数理统计、计算机网络、C语言还有个什么反正都要看,无论考得上考不上。

一些基本原则和观点

尊重客观规律,理论联系实际,一切以时间、地点、条件为转移,具体问题具体分析。

坚持以人为本,始终把他人满意不满意,他人高兴不高兴,他人的想法和可能采取的行动放在考虑的第一位,把人的因素放在第一位。

身体第一,这是一切折腾与妥协的根本底线,不容置疑。

时间宝贵,道路是曲折的,前途是光明的。

团结一切可以团结的力量。

基本矛盾

要正确处理好理想与现实之间的矛盾:

  • 无限折腾的欲望和有限的时间之间的矛盾
  • 极端反娱乐与娱乐环境之间的矛盾
  • 无限折腾与适度休息之间的矛盾
  • 不健康生活方式与锻炼和维护自身健康之间的矛盾
  • 漂泊闯荡和家庭羁绊之间的矛盾

Mon 07 Jan 2013 08:08:27 PM CST
By Reverland